package com.pablito.webapp.security;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import com.pablito.dao.UserDao;
import com.pablito.model.User;

public class LoginHandler implements AuthenticationFailureHandler, AuthenticationSuccessHandler {
	
	public static final String USERNAME_SESSION_KEY = "username";
	private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
	@Autowired
	private UserDao userDao;
	/**
	 * Clave para guardar errores en sesión.
	 */
	private String sessionErrorKey = "loginErrorKey";
	/**
	 * Clave de error {@code CredentialsExpiredException} 
	 */
	private String credentialsExpiredErrorKey = "error.credentialsExpired";
	private String credentialsExpiredUrl = "credentialsExpired";
	private String badCredentialsErrorKey = "error.badCredentials";
	private String badCredentialsUrl = "badCredentials";
	private String successLoginUrl = "successLogin";
	private Log log = LogFactory.getLog(getClass());
	
	
	@Override
	public void onAuthenticationFailure(HttpServletRequest request,	HttpServletResponse response, 
			AuthenticationException exception) throws IOException, ServletException {
		String username = request.getParameter("j_username");
		appendUsernameToSession(request, username);
		if (exception instanceof CredentialsExpiredException) {
			handleCredentialsExpired(request, response, username);
		}
		if (exception instanceof BadCredentialsException) {
			handleBadCredentials(request, response, username);
		}
	}

	@Override
	public void onAuthenticationSuccess(HttpServletRequest request,
			HttpServletResponse response, Authentication authentication)
			throws IOException, ServletException {
		clearSession(request);
		redirect(request, response, successLoginUrl);
	}
	
	private void handleCredentialsExpired(HttpServletRequest request, HttpServletResponse response, String username) 
			throws IOException {
		log.warn("Intento de login del usuario: " + username + " | CREDENCIALES EXPIRADAS...");
		redirect(request, response, credentialsExpiredUrl);
	}
	
	private void handleBadCredentials(HttpServletRequest request, HttpServletResponse response, String username) 
			throws IOException {
		try {
			User user = (User) userDao.loadUserByUsername(username);
			user.loginFailed();
			userDao.saveUser(user);
			log.warn("Intento de login del usuario: " + username + " | CREDENCIALES INCORRECTAS...");
		} catch (UsernameNotFoundException e) {
			log.error("Intento de login del usuario: " + username + " | USUARIO NO EXISTE...");
		} finally {
			appendErrorToSession(request, badCredentialsErrorKey);
		}
		
		redirect(request, response, badCredentialsUrl);
	}
	
	private void appendErrorToSession(HttpServletRequest request, String errorKey) {
		if (!StringUtils.isBlank(sessionErrorKey) && !StringUtils.isBlank(errorKey)) {
			request.getSession().setAttribute(sessionErrorKey, errorKey);
		}
	}
	
	private void appendUsernameToSession(HttpServletRequest request, String username) {
		request.getSession().setAttribute(USERNAME_SESSION_KEY, username);
	}
	
	private void clearSession(HttpServletRequest request) {
		request.getSession().removeAttribute(sessionErrorKey);	
		request.getSession().removeAttribute(USERNAME_SESSION_KEY);
	}
	
	private void redirect(HttpServletRequest request, HttpServletResponse response, String redirectUrl) 
			throws IOException {
		if (!StringUtils.isBlank(redirectUrl)) {
			log.info("Redireccionando a: " + redirectUrl);
//			response.sendRedirect(redirectUrl);
			redirectStrategy.sendRedirect(request, response, redirectUrl);
		}
	}

	public String getSessionErrorKey() {
		return sessionErrorKey;
	}

	public void setSessionErrorKey(String sessionErrorKey) {
		this.sessionErrorKey = sessionErrorKey;
	}

	public String getCredentialsExpiredErrorKey() {
		return credentialsExpiredErrorKey;
	}

	public void setCredentialsExpiredErrorKey(String credentialsExpiredErrorKey) {
		this.credentialsExpiredErrorKey = credentialsExpiredErrorKey;
	}

	public String getCredentialsExpiredUrl() {
		return credentialsExpiredUrl;
	}

	public void setCredentialsExpiredUrl(String credentialsExpiredUrl) {
		this.credentialsExpiredUrl = credentialsExpiredUrl;
	}

	public String getBadCredentialsUrl() {
		return badCredentialsUrl;
	}

	public void setBadCredentialsUrl(String badCredentialsUrl) {
		this.badCredentialsUrl = badCredentialsUrl;
	}

	public String getBadCredentialsErrorKey() {
		return badCredentialsErrorKey;
	}

	public void setBadCredentialsErrorKey(String badCredentialsErrorKey) {
		this.badCredentialsErrorKey = badCredentialsErrorKey;
	}

	public String getSuccessLoginUrl() {
		return successLoginUrl;
	}

	public void setSuccessLoginUrl(String successLoginUrl) {
		this.successLoginUrl = successLoginUrl;
	}
}